-module(client_redis_u).
-author("datian").

-behaviour(gen_server).

%% API
-export([start/1]).

%% gen_server callbacks
-export([init/1,
  handle_call/3,
  handle_cast/2,
  handle_info/2,
  terminate/2,
  code_change/3]).

-export([clean/0]).



-record(state, {uid}).
-record(user_info, {
  uid,
  age
}).

-define(PROCNAME, "cus_redis_").

start(Uid) ->
  gen_server:start_link({local, list_to_atom("client_user_" ++ Uid)}, ?MODULE, [Uid], []).


init([Uid]) ->
  io:format("started :~p~n", [Uid]),
  Rand = client_simu:random2(50),io:format("init rand:~p~n", [Rand]),
  erlang:send_after(Rand*1000, self(), {loop}),
  {ok, #state{uid=Uid}}.


handle_call(_Request, _From, State) ->
  {reply, ok, State}.

handle_cast(_Request, State) ->
  {noreply, State}.

handle_info({loop}, #state{uid=Uid}=State) ->
  erlang:send_after(10000, self(), {loop}),
  case get_user_info(Uid) of
    undefined ->
      Info2 = #user_info{uid=Uid, age=0};
    Info when is_binary(Info) ->
      Info2 = case cus_util:bitstring_to_term(Info) of
                undefined ->
                  #user_info{uid=Uid, age=0};
                InfoN ->
                  io:format("loop 1 : ~p~n", [InfoN]),
                  InfoN
              end;
    Info ->
      io:format("other:~p~n", [Info]),
      Info2 = #user_info{uid=Uid, age=0}
  end,
  io:format("loop 2 : ~p~n", [Info2]),
  #user_info{age=Age} = Info2,
  Info3 =
  case Info2 of
    #user_info{uid=Uid} ->
      Info2#user_info{uid=Uid, age=Age+10};
    _ ->
      #user_info{uid=Uid, age=0}
  end,
  set_user_info(Uid, cus_util:term_to_bitstring(Info3)),
  io:format("update user info:~p~n", [Info3]),
  {noreply, State};
handle_info(_Info, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->
  ok.

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.

%%====================
%%   api
%%====================



get_proc_name(Index) ->
  Name = ?PROCNAME ++ erlang:integer_to_list(Index),
  erlang:list_to_atom(Name).


get_redis_proc(Key) ->
  Index = erlang:phash(Key, 100),
  get_proc_name(Index).

get_user_info(Uid) ->
  ProcName = get_redis_proc(Uid),
  safe_q(ProcName, ["GET", "client_user_" ++ Uid]).

set_user_info(Uid, Info) ->
  ProcName = get_redis_proc(Uid),
  safe_q(ProcName, ["SET", "client_user_" ++ Uid, Info]).

safe_q(ProcName, Cmd) ->
  case whereis(ProcName) of
    undefined ->
      case eredis:start_link("127.0.0.1", 6379, 1, "") of
        {ok, Client} ->
          register(ProcName, Client),
          case eredis:q(ProcName, Cmd) of
            {ok, V} ->
              V;
            _Err -> undefined
          end;
        {error, Err} ->
          io:format("Failed to start redis client: ~p", [Err]),
          undefined
      end;
    _ ->
      case eredis:q(ProcName, Cmd) of
        {ok, V} ->
          V;
        _Err -> undefined
      end
  end.



clean() ->
  ProcName = get_redis_proc(1),
  safe_q(ProcName, ["DEL", "client_user_*"]).




